home *** CD-ROM | disk | FTP | other *** search
/ AMIGA-CD 2 / Amiga-CD - Volume 2.iso / gepackte_disketten / 1994 / 08_94_5.dms / 08_94_5.adf / term-4.0-Source.lha / termFileBuffer.c < prev    next >
C/C++ Source or Header  |  1994-07-06  |  22KB  |  1,153 lines

  1. /*
  2. **    termFileBuffer.c
  3. **
  4. **    Double-buffered file I/O routines
  5. **
  6. **    Copyright © 1990-1994 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Argument types. */
  13.  
  14. enum    {    ARG_NAME,ARG_MODE };
  15. enum    {    ARG_OFFSET,ARG_ORIGIN };
  16.  
  17.     /* Seek offsets. */
  18.  
  19. enum    {    SEEKFILE_SET,SEEKFILE_CURR,SEEKFILE_END };
  20.  
  21.     /* Command codes. */
  22.  
  23. enum    {    BUF_CLOSE,BUF_SEEK,BUF_FILL,BUF_FLUSH };
  24.  
  25.     /* ObtainInfo(struct Buffer *File):
  26.      *
  27.      *    Obtain information on the disk a buffered file
  28.      *    resides on.
  29.      */
  30.  
  31. STATIC VOID __regargs
  32. ObtainInfo(struct Buffer *File)
  33. {
  34.         /* Lock on the path available? */
  35.  
  36.     if(File -> DirLock)
  37.     {
  38.             /* Obtain information... */
  39.  
  40.         if(!Info(File -> DirLock,&File -> InfoData))
  41.         {
  42.                 /* No success, release resources. */
  43.  
  44.             UnLock(File -> DirLock);
  45.  
  46.             File -> DirLock = NULL;
  47.  
  48.             File -> InfoData . id_NumBlocks        = 0;
  49.             File -> InfoData . id_BytesPerBlock    = 0;
  50.         }
  51.     }
  52. }
  53.  
  54.     /* FileBufferServer():
  55.      *
  56.      *    Background process to handle the buffering
  57.      *    of a filehandle, automatically gets invoked
  58.      *    when a file is opened.
  59.      */
  60.  
  61. STATIC VOID __saveds
  62. FileBufferServer(VOID)
  63. {
  64.     struct MsgPort    *Port;
  65.     struct Buffer    *Buffer;
  66.     BYTE         Terminated = FALSE,
  67.              Done,
  68.              WasFull;
  69.     UBYTE        *String;
  70.     APTR         Data;
  71.     LONG         Length;
  72.     BPTR         SomeLock;
  73.  
  74.         /* Wait for startup message (-> Buffer). */
  75.  
  76.     Port = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
  77.  
  78.     WaitPort(Port);
  79.  
  80.     Buffer = (struct Buffer *)GetMsg(Port);
  81.  
  82.         /* Open the file and obtain a filehandle. */
  83.  
  84.     String = (STRPTR)Buffer -> ActionData[ARG_MODE];
  85.  
  86.     Buffer -> WriteAccess = TRUE;
  87.  
  88.         /* Put the message into the list. */
  89.  
  90.     ObtainSemaphore(&DoubleBufferSemaphore);
  91.  
  92.     AddTail(&DoubleBufferList,(struct Node *)Buffer);
  93.  
  94.     ReleaseSemaphore(&DoubleBufferSemaphore);
  95.  
  96.         /* Remember the opening date. */
  97.  
  98.     DateStamp(&Buffer -> OpenDate);
  99.  
  100.         /* Check for the open type. */
  101.  
  102.     switch(String[0])
  103.     {
  104.         case 'r':
  105.  
  106.             if(String[1] == '+')
  107.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  108.             else
  109.             {
  110.                 Buffer -> WriteAccess = FALSE;
  111.  
  112.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_OLDFILE);
  113.             }
  114.  
  115.             break;
  116.  
  117.         case 'w':
  118.  
  119.             if(String[1] == '+')
  120.             {
  121.                 if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  122.                 {
  123.                     UnLock(SomeLock);
  124.  
  125.                     DeleteFile((STRPTR)Buffer -> ActionData[ARG_NAME]);
  126.                 }
  127.  
  128.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  129.             }
  130.             else
  131.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  132.  
  133.             break;
  134.  
  135.         case 'a':
  136.  
  137.             if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  138.             {
  139.                 UnLock(SomeLock);
  140.  
  141.                 if(Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE))
  142.                 {
  143.                     if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  144.                     {
  145.                         Close(Buffer -> FileHandle);
  146.  
  147.                         Buffer -> FileHandle = NULL;
  148.                     }
  149.                 }
  150.             }
  151.             else
  152.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  153.  
  154.             break;
  155.     }
  156.  
  157.         /* Clear signal bit. */
  158.  
  159.     ClrSignal(SIG_COMMAND);
  160.  
  161.         /* Did the file open? */
  162.  
  163.     if(Buffer -> FileHandle)
  164.     {
  165.         Buffer -> Data        = Buffer -> DataBuffer[0];
  166.         Buffer -> DataCount    = 1;
  167.         Buffer -> Fresh        = TRUE;
  168.  
  169.             /* If not in write mode fill the buffers. */
  170.  
  171.         if(!Buffer -> WriteAccess)
  172.         {
  173.                 /* Fill the first one synchronously. */
  174.  
  175.             Buffer -> ReadBufFull    = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  176.             Buffer -> Read        = TRUE;
  177.             Buffer -> RealPosition    = Buffer -> ReadBufFull;
  178.  
  179.                 /* Restart caller. */
  180.  
  181.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  182.  
  183.                 /* Fill the second buffe asynchronously. */
  184.  
  185.             Buffer -> DataLength[1]    = Buffer -> Cached = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  186.             Buffer -> RealPosition += Buffer -> Cached;
  187.         }
  188.         else
  189.         {
  190.             UBYTE     TempBuffer[MAX_FILENAME_LENGTH],
  191.                 *Stop;
  192.             BPTR     TempLock;
  193.  
  194.             strcpy(TempBuffer,(STRPTR)Buffer -> ActionData[ARG_NAME]);
  195.  
  196.             Stop = PathPart(TempBuffer);
  197.  
  198.             *Stop = 0;
  199.  
  200.             if(TempLock = Lock(TempBuffer,ACCESS_READ))
  201.             {
  202.                 BPTR OldDir = CurrentDir(TempLock);
  203.  
  204.                 Buffer -> DirLock = Lock(":",ACCESS_READ);
  205.  
  206.                 CurrentDir(OldDir);
  207.  
  208.                 UnLock(TempLock);
  209.             }
  210.  
  211.             ObtainInfo(Buffer);
  212.  
  213.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  214.         }
  215.     }
  216.     else
  217.         Terminated = TRUE;
  218.  
  219.         /* Go into loop waiting for commands. */
  220.  
  221.     while(!Terminated)
  222.     {
  223.         Wait(SIG_COMMAND);
  224.  
  225.         Done = FALSE;
  226.  
  227.         Buffer -> Result = 0;
  228.  
  229.             /* Take care of each action. */
  230.  
  231.         switch(Buffer -> Action)
  232.         {
  233.                 /* Close the file, flush any dirty
  234.                  * buffers and exit.
  235.                  */
  236.  
  237.             case BUF_CLOSE:
  238.  
  239.                 Buffer -> Result = TRUE;
  240.  
  241.                 if(Buffer -> BufPosition && Buffer -> Written)
  242.                 {
  243.                     if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  244.                         Buffer -> Result = FALSE;
  245.                 }
  246.  
  247.                 if(!Close(Buffer -> FileHandle))
  248.                     Buffer -> Result = FALSE;
  249.  
  250.                 if(Buffer -> DirLock)
  251.                     UnLock(Buffer -> DirLock);
  252.  
  253.                 Terminated = TRUE;
  254.  
  255.                 break;
  256.  
  257.                 /* Seek to a specific file position. */
  258.  
  259.             case BUF_SEEK:
  260.  
  261.                 Buffer -> Result = 0;
  262.  
  263.                     /* Do nothing if buffer is still
  264.                      * untouched and we are required
  265.                      * to seek back to the beginning
  266.                      * of the file.
  267.                      */
  268.  
  269.                 if(Buffer -> Fresh && !Buffer -> ActionData[ARG_OFFSET] && Buffer -> ActionData[ARG_ORIGIN] == SEEKFILE_SET)
  270.                 {
  271.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  272.  
  273.                     Done = TRUE;
  274.                 }
  275.                 else
  276.                 {
  277.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  278.                     Buffer -> Read        = FALSE;
  279.  
  280.                     if(Buffer -> BufPosition && Buffer -> Written)
  281.                     {
  282.                         if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  283.                             Buffer -> Result = -1;
  284.                         else
  285.                             ObtainInfo(Buffer);
  286.                     }
  287.  
  288.                     if(!Buffer -> Result)
  289.                     {
  290.                         Buffer -> Result = Buffer -> RealPosition - (Buffer -> ReadBufFull + Buffer -> Cached);
  291.  
  292.                         switch(Buffer -> ActionData[ARG_ORIGIN])
  293.                         {
  294.                             case SEEKFILE_SET:
  295.  
  296.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
  297.                                     Buffer -> RealPosition = Buffer -> ActionData[ARG_OFFSET];
  298.                                 else
  299.                                     Buffer -> Result = -1;
  300.  
  301.                                 break;
  302.  
  303.                             case SEEKFILE_CURR:
  304.  
  305.                                 if(!Buffer -> WriteAccess && Buffer -> ActionData[ARG_OFFSET] >= 0 && Buffer -> ReadBufFull - Buffer -> ActionData[ARG_OFFSET] >= 0)
  306.                                 {
  307.                                     Buffer -> ReadBufFull    -= Buffer -> ActionData[ARG_OFFSET];
  308.                                     Buffer -> Data        += Buffer -> ActionData[ARG_OFFSET];
  309.  
  310.                                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  311.  
  312.                                     Done = TRUE;
  313.  
  314.                                     break;
  315.                                 }
  316.  
  317.                                 if(Seek(Buffer -> FileHandle,-(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
  318.                                     Buffer -> RealPosition += -(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET];
  319.                                 else
  320.                                     Buffer -> Result = -1;
  321.  
  322.                                 break;
  323.  
  324.                             case SEEKFILE_END:
  325.  
  326.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_END) != -1)
  327.                                     Buffer -> RealPosition = Seek(Buffer -> FileHandle,0,OFFSET_CURRENT);
  328.                                 else
  329.                                     Buffer -> Result = -1;
  330.  
  331.                                 break;
  332.  
  333.                             default:
  334.  
  335.                                 Buffer -> Result = -1;
  336.                         }
  337.  
  338.                         Buffer -> ReadBufFull = 0;
  339.  
  340.                         if(Buffer -> Result != -1)
  341.                         {
  342.                             Buffer -> Data        = Buffer -> DataBuffer[0];
  343.                             Buffer -> DataCount    = 1;
  344.  
  345.                             if(!Buffer -> WriteAccess)
  346.                             {
  347.                                 Buffer -> ReadBufFull     = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  348.                                 Buffer -> WriteBufFull     = 0;
  349.                                 Buffer -> Read         = TRUE;
  350.                                 Buffer -> RealPosition    += Buffer -> ReadBufFull;
  351.  
  352.                                 if(Buffer -> ReadBufFull)
  353.                                 {
  354.                                     Buffer -> Cached = Buffer -> DataLength[1] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  355.  
  356.                                     Buffer -> RealPosition += Buffer -> Cached;
  357.                                 }
  358.                             }
  359.                         }
  360.                         else
  361.                             Buffer -> LastActionFailed = TRUE;
  362.                     }
  363.                     else
  364.                         Buffer -> ReadBufFull = 0;
  365.  
  366.                     Buffer -> BufPosition    = 0;
  367.                     Buffer -> Written    = FALSE;
  368.                 }
  369.  
  370.                 break;
  371.  
  372.                 /* Fill the buffer with fresh data. */
  373.  
  374.             case BUF_FILL:
  375.  
  376.                 Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  377.                 Buffer -> ReadBufFull    = Buffer -> DataLength[Buffer -> DataCount];
  378.                 Buffer -> WriteBufFull    = 0;
  379.                 Buffer -> BufPosition    = 0;
  380.                 Buffer -> Read        = TRUE;
  381.                 Buffer -> Written    = FALSE;
  382.                 Buffer -> Fresh        = FALSE;
  383.  
  384.                 if(Buffer -> ReadBufFull)
  385.                     WasFull = TRUE;
  386.                 else
  387.                     WasFull = FALSE;
  388.  
  389.                     /* The buffer contents have been
  390.                      * swapped, now wake the caller
  391.                      * up and fill the next buffer
  392.                      * asynchronously.
  393.                      */
  394.  
  395.                 Signal(Buffer -> Caller,SIG_HANDSHAKE);
  396.  
  397.                 Done = TRUE;
  398.  
  399.                 if(WasFull)
  400.                 {
  401.                     Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  402.  
  403.                     Buffer -> Cached = Buffer -> DataLength[Buffer -> DataCount] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[Buffer -> DataCount],Buffer -> BufLength);
  404.  
  405.                     Buffer -> RealPosition += Buffer -> Cached;
  406.  
  407.                     if(!Buffer -> DataLength[Buffer -> DataCount])
  408.                     {
  409.                         if(IoErr())
  410.                             Buffer -> LastActionFailed = TRUE;
  411.                     }
  412.                 }
  413.  
  414.                 break;
  415.  
  416.                 /* Flush the contents of the buffer to disk. */
  417.  
  418.             case BUF_FLUSH:
  419.  
  420.                 if(Buffer -> BufPosition && Buffer -> Written)
  421.                 {
  422.                     Data            = Buffer -> Data;
  423.                     Length            = Buffer -> BufPosition;
  424.  
  425.                     Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  426.                     Buffer -> DataCount    = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  427.  
  428.                     Buffer -> ReadBufFull    = 0;
  429.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  430.                     Buffer -> BufPosition    = 0;
  431.                     Buffer -> Read        = FALSE;
  432.                     Buffer -> Written    = FALSE;
  433.  
  434.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  435.  
  436.                     Done = TRUE;
  437.  
  438.                     if(Write(Buffer -> FileHandle,Data,Length) != Length)
  439.                         Buffer -> LastActionFailed = TRUE;
  440.                     else
  441.                     {
  442.                         ObtainInfo(Buffer);
  443.  
  444.                         Buffer -> RealPosition += Length;
  445.                     }
  446.                 }
  447.                 else
  448.                 {
  449.                     Buffer -> ReadBufFull    = 0;
  450.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  451.                     Buffer -> BufPosition    = 0;
  452.                     Buffer -> Read        = FALSE;
  453.                     Buffer -> Written    = FALSE;
  454.                 }
  455.  
  456.                 Buffer -> Fresh = FALSE;
  457.  
  458.                 break;
  459.         }
  460.  
  461.             /* Ring back if necessary. */
  462.  
  463.         if(!Done && !Terminated)
  464.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  465.     }
  466.  
  467.         /* Remove the message from the list. */
  468.  
  469.     ObtainSemaphore(&DoubleBufferSemaphore);
  470.  
  471.     Remove((struct Node *)Buffer);
  472.  
  473.     ReleaseSemaphore(&DoubleBufferSemaphore);
  474.  
  475.         /* Lock & quit. */
  476.  
  477.     Forbid();
  478.  
  479.     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  480. }
  481.  
  482.     /* BufferFill(struct Buffer *Buffer):
  483.      *
  484.      *    Fills a given buffer with fresh data.
  485.      */
  486.  
  487. STATIC BYTE __inline
  488. BufferFill(struct Buffer *Buffer)
  489. {
  490.     if(Buffer -> LastActionFailed)
  491.         return(FALSE);
  492.     else
  493.     {
  494.         if(!Buffer -> ReadBufFull)
  495.         {
  496.             Buffer -> Action = BUF_FILL;
  497.  
  498.             Forbid();
  499.  
  500.             Signal(Buffer -> Child,SIG_COMMAND);
  501.  
  502.             ClrSignal(SIG_HANDSHAKE);
  503.  
  504.             Wait(SIG_HANDSHAKE);
  505.  
  506.             Permit();
  507.         }
  508.  
  509.         return(TRUE);
  510.     }
  511. }
  512.  
  513.     /* IsValidBuffer(struct Buffer *Buffer):
  514.      *
  515.      *    Scans the double buffered file list for
  516.      *    a valid entry.
  517.      */
  518.  
  519. STATIC BYTE __inline
  520. IsValidBuffer(struct Buffer *Buffer)
  521. {
  522.     BYTE         GotIt = FALSE;
  523.     struct Node    *Node;
  524.  
  525.     ObtainSemaphore(&DoubleBufferSemaphore);
  526.  
  527.     Node = DoubleBufferList . lh_Head;
  528.  
  529.     while(Node -> ln_Succ)
  530.     {
  531.         if(Buffer == (struct Buffer *)Node)
  532.         {
  533.             GotIt = TRUE;
  534.  
  535.             break;
  536.         }
  537.  
  538.         Node = Node -> ln_Succ;
  539.     }
  540.  
  541.     ReleaseSemaphore(&DoubleBufferSemaphore);
  542.  
  543.     return(GotIt);
  544. }
  545.  
  546.     /* OpenFileSimple(STRPTR Name,STRPTR AccessMode):
  547.      *
  548.      *    Open simple (unbuffered) file.
  549.      */
  550.  
  551. STATIC struct Buffer * __regargs
  552. OpenFileSimple(STRPTR Name,STRPTR AccessMode)
  553. {
  554.     struct Buffer *Buffer;
  555.  
  556.         /* Allocate buffer handle (dummy). */
  557.  
  558.     if(Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer),MEMF_ANY | MEMF_CLEAR))
  559.     {
  560.         BPTR SomeLock;
  561.  
  562.             /* Provide basic information. */
  563.  
  564.         DateStamp(&Buffer -> OpenDate);
  565.  
  566.         Buffer -> WriteAccess = TRUE;
  567.  
  568.         Buffer -> SimpleIO = TRUE;
  569.  
  570.             /* Open the file. */
  571.  
  572.         switch(AccessMode[0])
  573.         {
  574.             case 'r':
  575.  
  576.                 if(AccessMode[1] == '+')
  577.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  578.                 else
  579.                 {
  580.                     Buffer -> WriteAccess = FALSE;
  581.  
  582.                     Buffer -> FileHandle = Open(Name,MODE_OLDFILE);
  583.                 }
  584.  
  585.                 break;
  586.  
  587.             case 'w':
  588.  
  589.                 if(AccessMode[1] == '+')
  590.                 {
  591.                     if(SomeLock = Lock(Name,ACCESS_WRITE))
  592.                     {
  593.                         UnLock(SomeLock);
  594.  
  595.                         DeleteFile(Name);
  596.                     }
  597.  
  598.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  599.                 }
  600.                 else
  601.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  602.  
  603.                 break;
  604.  
  605.             case 'a':
  606.  
  607.                 if(SomeLock = Lock(Name,ACCESS_WRITE))
  608.                 {
  609.                     UnLock(SomeLock);
  610.  
  611.                     if(Buffer -> FileHandle = Open(Name,MODE_READWRITE))
  612.                     {
  613.                         if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  614.                         {
  615.                             Close(Buffer -> FileHandle);
  616.  
  617.                             Buffer -> FileHandle = NULL;
  618.                         }
  619.                     }
  620.                 }
  621.                 else
  622.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  623.  
  624.                 break;
  625.         }
  626.  
  627.             /* Did we succeed in opening the file? */
  628.  
  629.         if(Buffer -> FileHandle)
  630.         {
  631.                 /* Try to obtain a lock on the destination directory. */
  632.  
  633.             if(Buffer -> WriteAccess)
  634.             {
  635.                 UBYTE     TempBuffer[MAX_FILENAME_LENGTH],
  636.                     *Stop;
  637.                 BPTR     TempLock;
  638.  
  639.                 strcpy(TempBuffer,(STRPTR)Buffer -> ActionData[ARG_NAME]);
  640.  
  641.                 Stop = PathPart(TempBuffer);
  642.  
  643.                 *Stop = 0;
  644.  
  645.                 if(TempLock = Lock(TempBuffer,ACCESS_READ))
  646.                 {
  647.                     BPTR OldDir = CurrentDir(TempLock);
  648.  
  649.                     Buffer -> DirLock = Lock(":",ACCESS_READ);
  650.  
  651.                     CurrentDir(OldDir);
  652.  
  653.                     UnLock(TempLock);
  654.                 }
  655.  
  656.                 ObtainInfo(Buffer);
  657.             }
  658.  
  659.                 /* Link the file into the list. */
  660.  
  661.             ObtainSemaphore(&DoubleBufferSemaphore);
  662.  
  663.             AddTail(&DoubleBufferList,(struct Node *)Buffer);
  664.  
  665.             ReleaseSemaphore(&DoubleBufferSemaphore);
  666.  
  667.             return(Buffer);
  668.         }
  669.         else
  670.             FreeVecPooled(Buffer);
  671.     }
  672.  
  673.     return(NULL);
  674. }
  675.  
  676.     /* OpenFileBuffered(STRPTR Name,STRPTR AccessMode):
  677.      *
  678.      *    Open double-buffered file.
  679.      */
  680.  
  681. STATIC struct Buffer * __regargs
  682. OpenFileBuffered(STRPTR Name,STRPTR AccessMode)
  683. {
  684.     struct Buffer    *Buffer;
  685.     LONG         Size;
  686.  
  687.     Size = Config -> MiscConfig -> IOBufferSize;
  688.  
  689.         /* Allocate the buffer data. */
  690.  
  691.     do
  692.     {
  693.         Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer) + Size * BUFFER_NUMBER,MEMF_ANY | MEMF_CLEAR);
  694.  
  695.         Size /= 2;
  696.     }
  697.     while(!Buffer && Size > 2048);
  698.  
  699.     if(Buffer)
  700.     {
  701.         struct Process    *Process;
  702.         WORD         i;
  703.  
  704.             /* Set up the first buffer. */
  705.  
  706.         Buffer -> DataBuffer[0] = (STRPTR)(Buffer + 1);
  707.  
  708.             /* Set up the individual buffers. */
  709.  
  710.         for(i = 1 ; i < BUFFER_NUMBER ; i++)
  711.             Buffer -> DataBuffer[i] = Buffer -> DataBuffer[i - 1] + Config -> MiscConfig -> IOBufferSize;
  712.  
  713.         Buffer -> BufLength    = Config -> MiscConfig -> IOBufferSize;
  714.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  715.  
  716.             /* Create the asynchronous file server. */
  717.  
  718.         if(!(Process = CreateNewProcTags(
  719.             NP_Entry,    FileBufferServer,
  720.             NP_Name,    "term File Process",
  721.             NP_Priority,    SysBase -> ThisTask -> tc_Node . ln_Pri,
  722.             NP_StackSize,    8192,
  723.             NP_WindowPtr,    -1,
  724.         TAG_DONE)))
  725.         {
  726.             FreeVecPooled(Buffer);
  727.  
  728.             return(NULL);
  729.         }
  730.  
  731.             /* Set up the message header. */
  732.  
  733.         Buffer -> Message . mn_Length    = sizeof(struct Buffer);
  734.  
  735.         Buffer -> ActionData[ARG_NAME]    = (LONG)Name;
  736.         Buffer -> ActionData[ARG_MODE]    = (LONG)AccessMode;
  737.  
  738.         Buffer -> Child            = Process;
  739.         Buffer -> Caller        = (struct Process *)SysBase -> ThisTask;
  740.  
  741.         Forbid();
  742.  
  743.             /* Send it to the waiting server process. */
  744.  
  745.         PutMsg(&Process -> pr_MsgPort,&Buffer -> Message);
  746.  
  747.             /* Wait for ringback. */
  748.  
  749.         ClrSignal(SIG_HANDSHAKE);
  750.  
  751.         Wait(SIG_HANDSHAKE);
  752.  
  753.         Permit();
  754.  
  755.             /* Do we have a valid filehandle? */
  756.  
  757.         if(!Buffer -> FileHandle)
  758.         {
  759.             FreeVecPooled(Buffer);
  760.  
  761.             return(NULL);
  762.         }
  763.         else
  764.             return(Buffer);
  765.     }
  766.  
  767.     return(NULL);
  768. }
  769.  
  770.     /* BPrintf():
  771.      *
  772.      *    Prints text into a buffered file.
  773.      */
  774.  
  775. LONG __stdargs
  776. BPrintf(struct Buffer *Buffer,STRPTR Format,...)
  777. {
  778.     UBYTE    String[256];
  779.     va_list    VarArgs;
  780.  
  781.     va_start(VarArgs,Format);
  782.     VSPrintf(String,Format,VarArgs);
  783.     va_end(VarArgs);
  784.  
  785.     return(BufferWrite(Buffer,String,strlen(String)));
  786. }
  787.  
  788.     /* BufferFlush(struct Buffer *Buffer):
  789.      *
  790.      *    Flush the contents of a given buffer to disk.
  791.      */
  792.  
  793. BYTE __regargs
  794. BufferFlush(struct Buffer *Buffer)
  795. {
  796.     if(Buffer -> LastActionFailed)
  797.         return(FALSE);
  798.     else
  799.     {
  800.         if(Buffer -> BufPosition && Buffer -> Written)
  801.         {
  802.             Buffer -> Action = BUF_FLUSH;
  803.  
  804.             Forbid();
  805.  
  806.             Signal(Buffer -> Child,SIG_COMMAND);
  807.  
  808.             ClrSignal(SIG_HANDSHAKE);
  809.  
  810.             Wait(SIG_HANDSHAKE);
  811.  
  812.             Permit();
  813.         }
  814.  
  815.         return(TRUE);
  816.     }
  817. }
  818.  
  819.     /* BufferClose(struct Buffer *Buffer):
  820.      *
  821.      *    Close a buffered filehandle.
  822.      */
  823.  
  824. BYTE __regargs
  825. BufferClose(struct Buffer *Buffer)
  826. {
  827.     if(IsValidBuffer(Buffer))
  828.     {
  829.         BYTE Success;
  830.  
  831.             /* Unbuffered file handle? */
  832.  
  833.         if(Buffer -> SimpleIO)
  834.         {
  835.                 /* Drop the destination drawer lock. */
  836.  
  837.             if(Buffer -> DirLock)
  838.                 UnLock(Buffer -> DirLock);
  839.  
  840.                 /* Close the file. */
  841.  
  842.             if(Close(Buffer -> FileHandle))
  843.                 Success = TRUE;
  844.             else
  845.                 Success = FALSE;
  846.  
  847.                 /* Unlink the handle. */
  848.  
  849.             ObtainSemaphore(&DoubleBufferSemaphore);
  850.  
  851.             Remove((struct Node *)Buffer);
  852.  
  853.             ReleaseSemaphore(&DoubleBufferSemaphore);
  854.         }
  855.         else
  856.         {
  857.             Buffer -> Action = BUF_CLOSE;
  858.  
  859.             Forbid();
  860.  
  861.             Signal(Buffer -> Child,SIG_COMMAND);
  862.  
  863.             ClrSignal(SIG_HANDSHAKE);
  864.  
  865.             Wait(SIG_HANDSHAKE);
  866.  
  867.             Permit();
  868.  
  869.             Success = Buffer -> Result;
  870.         }
  871.  
  872.         FreeVecPooled(Buffer);
  873.  
  874.         return(Success);
  875.     }
  876.     else
  877.         return(FALSE);
  878. }
  879.  
  880.     /* BufferOpen(STRPTR Name,STRPTR AccessMode):
  881.      *
  882.      *    Open a file for buffered I/O.
  883.      */
  884.  
  885. struct Buffer * __regargs
  886. BufferOpen(STRPTR Name,STRPTR AccessMode)
  887. {
  888.         /* Simple file handling? */
  889.  
  890.     if(Config -> MiscConfig -> SimpleIO)
  891.         return(OpenFileSimple(Name,AccessMode));
  892.     else
  893.     {
  894.         struct Buffer *Buffer;
  895.  
  896.             /* Try to open a buffered file, if unsuccessful
  897.              * fall back to simple file I/O.
  898.              */
  899.  
  900.         if(!(Buffer = OpenFileBuffered(Name,AccessMode)))
  901.             Buffer = OpenFileSimple(Name,AccessMode);
  902.  
  903.         return(Buffer);
  904.     }
  905. }
  906.  
  907.     /* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
  908.      *
  909.      *    Move the read/write pointer to a specific position
  910.      *    in a file (not really buffered).
  911.      */
  912.  
  913. BYTE __regargs
  914. BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
  915. {
  916.     if(Buffer -> SimpleIO)
  917.     {
  918.         if(Seek(Buffer -> FileHandle,Offset,Origin) == -1)
  919.             return(FALSE);
  920.         else
  921.             return(TRUE);
  922.     }
  923.     else
  924.     {
  925.         Buffer -> Action            = BUF_SEEK;
  926.         Buffer -> ActionData[ARG_OFFSET]    = Offset;
  927.         Buffer -> ActionData[ARG_ORIGIN]    = Origin;
  928.  
  929.         Forbid();
  930.  
  931.         Signal(Buffer -> Child,SIG_COMMAND);
  932.  
  933.         ClrSignal(SIG_HANDSHAKE);
  934.  
  935.         Wait(SIG_HANDSHAKE);
  936.  
  937.         Permit();
  938.  
  939.         if(Buffer -> Result == -1)
  940.             return(FALSE);
  941.         else
  942.             return(TRUE);
  943.     }
  944. }
  945.  
  946.     /* BufferRead():
  947.      *
  948.      *    Read data from a file (buffered).
  949.      */
  950.  
  951. LONG __regargs
  952. BufferRead(struct Buffer *Buffer,STRPTR Destination,LONG Size)
  953. {
  954.     if(Buffer -> SimpleIO)
  955.     {
  956.         LONG Bytes;
  957.  
  958.         Buffer -> Used = TRUE;
  959.  
  960.         if((Bytes = Read(Buffer -> FileHandle,Destination,Size)) < 0)
  961.             Bytes = 0;
  962.  
  963.         return(Bytes);
  964.     }
  965.     else
  966.     {
  967.         LONG     BytesRead = 0,ToCopy,BufPosition,ReadBufFull;
  968.         UBYTE    *Data;
  969.  
  970.             /* If there is still data to be written in
  971.              * the buffer, write it.
  972.              */
  973.  
  974.         if(Buffer -> Written)
  975.         {
  976.             if(!BufferFlush(Buffer))
  977.                 return(0);
  978.         }
  979.  
  980.             /* Set up for read access. */
  981.  
  982.         BufPosition    = Buffer -> BufPosition;
  983.         ReadBufFull    = Buffer -> ReadBufFull;
  984.         Data        = &Buffer -> Data[BufPosition];
  985.  
  986.             /* Remember access. */
  987.  
  988.         Buffer -> Used    = TRUE;
  989.  
  990.             /* Continue until all data has been processed. */
  991.  
  992.         while(Size)
  993.         {
  994.                 /* Determine number of bytes to transfer. */
  995.  
  996.             if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
  997.             {
  998.                 CopyMem(Data,Destination,ToCopy);
  999.  
  1000.                 Size        -= ToCopy;
  1001.                 BufPosition    += ToCopy;
  1002.                 ReadBufFull    -= ToCopy;
  1003.                 Destination    += ToCopy;
  1004.                 Data        += ToCopy;
  1005.                 BytesRead    += ToCopy;
  1006.             }
  1007.             else
  1008.             {
  1009.                     /* Refill buffer with data. */
  1010.  
  1011.                 Buffer -> BufPosition    = BufPosition;
  1012.                 Buffer -> ReadBufFull    = ReadBufFull;
  1013.  
  1014.                 if(!BufferFill(Buffer))
  1015.                     return(BytesRead);
  1016.  
  1017.                 if(!Buffer -> ReadBufFull)
  1018.                 {
  1019.                     Buffer -> BufPosition = BufPosition;
  1020.  
  1021.                     return(BytesRead);
  1022.                 }
  1023.  
  1024.                     /* Pick up new data. */
  1025.  
  1026.                 BufPosition        = Buffer -> BufPosition;
  1027.                 ReadBufFull        = Buffer -> ReadBufFull;
  1028.                 Data            = Buffer -> Data;
  1029.             }
  1030.         }
  1031.  
  1032.             /* Install new data. */
  1033.  
  1034.         Buffer -> BufPosition    = BufPosition;
  1035.         Buffer -> ReadBufFull    = ReadBufFull;
  1036.  
  1037.         return(BytesRead);
  1038.     }
  1039. }
  1040.  
  1041.     /* BufferWrite():
  1042.      *
  1043.      *    Write data to a file (buffered).
  1044.      */
  1045.  
  1046. LONG __regargs
  1047. BufferWrite(struct Buffer *Buffer,STRPTR Source,LONG Size)
  1048. {
  1049.     if(Buffer -> SimpleIO)
  1050.     {
  1051.         LONG Bytes;
  1052.  
  1053.         Buffer -> Used = TRUE;
  1054.  
  1055.         Buffer -> WriteAccess = TRUE;
  1056.  
  1057.         if((Bytes = Write(Buffer -> FileHandle,Source,Size)) < 0)
  1058.             Bytes = 0;
  1059.         else
  1060.         {
  1061.             Buffer -> BufPosition += Bytes;
  1062.  
  1063.             if(Buffer -> BufPosition >= Config -> MiscConfig -> IOBufferSize)
  1064.             {
  1065.                 Buffer -> BufPosition = 0;
  1066.  
  1067.                 ObtainInfo(Buffer);
  1068.             }
  1069.         }
  1070.  
  1071.         return(Bytes);
  1072.     }
  1073.     else
  1074.     {
  1075.         LONG     BytesWritten = 0,ToCopy,BufPosition,WriteBufFull;
  1076.         UBYTE    *Data;
  1077.  
  1078.             /* If there is still read data in the buffer,
  1079.              * reset the control information.
  1080.              */
  1081.  
  1082.         if(Buffer -> Read)
  1083.         {
  1084.             Buffer -> WriteBufFull    = Buffer -> BufLength;
  1085.             Buffer -> BufPosition    = 0;
  1086.             Buffer -> Read        = FALSE;
  1087.         }
  1088.  
  1089.             /* Set up for write access. */
  1090.  
  1091.         Buffer -> Written = TRUE;
  1092.  
  1093.         BufPosition    = Buffer -> BufPosition;
  1094.         WriteBufFull    = Buffer -> WriteBufFull;
  1095.         Data        = &Buffer -> Data[BufPosition];
  1096.  
  1097.             /* Remember access. */
  1098.  
  1099.         Buffer -> Used    = TRUE;
  1100.  
  1101.             /* Continue until all data has been processed. */
  1102.  
  1103.         while(Size)
  1104.         {
  1105.                 /* Determine number of bytes to transfer. */
  1106.  
  1107.             if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
  1108.             {
  1109.                 CopyMem(Source,Data,ToCopy);
  1110.  
  1111.                 Size        -= ToCopy;
  1112.                 BufPosition    += ToCopy;
  1113.                 WriteBufFull    -= ToCopy;
  1114.                 Source        += ToCopy;
  1115.                 Data        += ToCopy;
  1116.                 BytesWritten    += ToCopy;
  1117.             }
  1118.             else
  1119.             {
  1120.                     /* Flush the contents of the
  1121.                      * write buffer.
  1122.                      */
  1123.  
  1124.                 Buffer -> BufPosition    = BufPosition;
  1125.                 Buffer -> WriteBufFull    = WriteBufFull;
  1126.  
  1127.                 if(!BufferFlush(Buffer))
  1128.                     return(BytesWritten);
  1129.  
  1130.                     /* Pick up new data. */
  1131.  
  1132.                 BufPosition        = Buffer -> BufPosition;
  1133.                 WriteBufFull        = Buffer -> WriteBufFull;
  1134.                 Data            = Buffer -> Data;
  1135.  
  1136.                     /* Important - or BufferFlush() won't
  1137.                      * write the final buffer contents when
  1138.                      * the buffered file handle is freed up.
  1139.                      */
  1140.  
  1141.                 Buffer -> Written = TRUE;
  1142.             }
  1143.         }
  1144.  
  1145.             /* Install new data. */
  1146.  
  1147.         Buffer -> BufPosition    = BufPosition;
  1148.         Buffer -> WriteBufFull    = WriteBufFull;
  1149.  
  1150.         return(BytesWritten);
  1151.     }
  1152. }
  1153.